package bll

import (
	"fmt"
	"sort"

	. "7qule.com/sd3/CrossServer/src/bll/challenge/model"
	"7qule.com/sd3/CrossServer/src/common/onlinelog"
	"7qule.com/sd3/CrossServer/src/common/systemConstant"
	"public.com/goutil/syncUtil"
)

const (
	TopThree            = 3 // 前三名
	FourPeopleAheadOfMe = 4 // 我前面的四个人
	TwoPeopleBehindMe   = 2 // 我后面的两个人
)

type globalChallengeStageSlice struct {
	// 页签信息
	data challengeSlice

	// 数据同步对象
	dataLock *syncUtil.RWLocker
}

// 定义排序对象
type challengeSlice []*GlobalChallengeModel

//
// Len
// @Description:获取长度
// @receiver this
// @return int:长度
//
func (this challengeSlice) Len() int {
	return len(this)
}

//
// Less
// @Description:排序顺序
// @receiver this
// @param i:前者
// @param j:后者
// @return bool:是否大于
//
func (this challengeSlice) Less(i, j int) bool {
	return this[i].Rank < this[j].Rank
}

//
// Swap
// @Description:交换
// @receiver this
// @param i:前者
// @param j:后者
//
func (this challengeSlice) Swap(i, j int) {
	this[i], this[j] = this[j], this[i]
}

//
// Sort
// @Description:切片排序
// @receiver this
//
func (this *globalChallengeStageSlice) Sort() {
	sort.Sort(this.data)
}

//
// NewGlobalChallengeStageSlice
// @Description:新建globalChallengeStageSlice对象
// @return *globalChallengeStageSlice:globalChallengeStageSlice对象
//
func NewGlobalChallengeStageSlice() *globalChallengeStageSlice {
	return &globalChallengeStageSlice{
		make(challengeSlice, 0),
		syncUtil.NewRWLocker(),
	}
}

//
// GetData
// @Description:获取数据
// @receiver this
// @return challengeSlice:页签数据
//
func (this *globalChallengeStageSlice) GetData() challengeSlice {
	return this.data
}

//
// GetChallengeStage
// @Description:获取当前页签的擂台数据
// @receiver this
// @param rank:排名
// @return challengeSlice:页签数据
//
func (this *globalChallengeStageSlice) GetChallengeStage(rank int) challengeSlice {
	playerStageSlice := challengeSlice{}

	if isOk, prevStack, currStack := this.dataLock.RLock(systemConstant.DefaultLockTime); isOk == false {
		errMsg := fmt.Sprintf("Lock timeout! \n上一个堆栈:\n%s  \n当前堆栈:\n%s", prevStack, currStack)
		onlinelog.ErrorLog(errMsg)
		panic(errMsg)
	}
	defer this.dataLock.RUnlock()

	if rank < TopThree+FourPeopleAheadOfMe+1 {
		playerStageSlice = this.data[0:BaseChallengeStageLenModelBll.GetData()]
		return playerStageSlice
	}

	if rank == len(this.data) {
		playerStageSlice = append(playerStageSlice, this.data[:TopThree]...)
		playerStageSlice = append(playerStageSlice, this.data[rank-BaseChallengeStageLenModelBll.GetData()+TopThree:]...)
		return playerStageSlice
	}

	playerStageSlice = append(playerStageSlice, this.data[:TopThree]...)
	playerStageSlice = append(playerStageSlice, this.data[rank-1-FourPeopleAheadOfMe:rank-1+TwoPeopleBehindMe+1]...)

	return playerStageSlice
}

//
// GetChallengeStageLen
// @Description:获取页签的长度
// @receiver this
// @return int:页签长度
//
func (this *globalChallengeStageSlice) GetChallengeStageLen() int {
	if isOk, prevStack, currStack := this.dataLock.RLock(systemConstant.DefaultLockTime); isOk == false {
		errMsg := fmt.Sprintf("Lock timeout! \n上一个堆栈:\n%s  \n当前堆栈:\n%s", prevStack, currStack)
		onlinelog.ErrorLog(errMsg)
		panic(errMsg)
	}
	defer this.dataLock.RUnlock()

	return len(this.data)
}

//
// AddChallengeStageLast
// @Description:添加用户到页签的末尾
// @receiver this
// @param playerChallengeData:用户擂台数据
//
func (this *globalChallengeStageSlice) AddChallengeStageLast(playerChallengeData *GlobalChallengeModel) {
	if isOk, prevStack, currStack := this.dataLock.Lock(systemConstant.DefaultLockTime); isOk == false {
		errMsg := fmt.Sprintf("Lock timeout! \n上一个堆栈:\n%s  \n当前堆栈:\n%s", prevStack, currStack)
		onlinelog.ErrorLog(errMsg)
		panic(errMsg)
	}
	defer this.dataLock.Unlock()

	this.data = append(this.data, playerChallengeData)
}

//
// GetChallengePlayerByRank
// @Description:根据排名找玩家
// @receiver this
// @param rank:排名
// @return *GlobalChallengeModel:玩家
//
func (this *globalChallengeStageSlice) GetChallengePlayerByRank(rank int) *GlobalChallengeModel {
	if rank > len(this.data) {
		return nil
	}

	if isOk, prevStack, currStack := this.dataLock.RLock(systemConstant.DefaultLockTime); isOk == false {
		errMsg := fmt.Sprintf("Lock timeout! \n上一个堆栈:\n%s  \n当前堆栈:\n%s", prevStack, currStack)
		onlinelog.ErrorLog(errMsg)
		panic(errMsg)
	}
	defer this.dataLock.RUnlock()

	return this.data[rank-1]
}

//
// ExchangeChallengePlayer
// @Description:交换排名
// @receiver this
// @param playerRank:挑战者排名
// @param challengedRank:被挑战者排名
//
func (this *globalChallengeStageSlice) ExchangeChallengePlayer(playerRank, challengedRank int) {
	if isOk, prevStack, currStack := this.dataLock.Lock(systemConstant.DefaultLockTime); isOk == false {
		errMsg := fmt.Sprintf("Lock timeout! \n上一个堆栈:\n%s  \n当前堆栈:\n%s", prevStack, currStack)
		onlinelog.ErrorLog(errMsg)
		panic(errMsg)
	}
	defer this.dataLock.Unlock()

	this.data[playerRank-1], this.data[challengedRank-1] = this.data[challengedRank-1], this.data[playerRank-1]
}

//
// GetChallengeStageTopTen
// @Description:获取已经打过的前十数据
// @receiver this
// @return challengeSlice:前十数据
//
func (this *globalChallengeStageSlice) GetChallengeStageTopTen() challengeSlice {
	if isOk, prevStack, currStack := this.dataLock.RLock(systemConstant.DefaultLockTime); isOk == false {
		errMsg := fmt.Sprintf("Lock timeout! \n上一个堆栈:\n%s  \n当前堆栈:\n%s", prevStack, currStack)
		onlinelog.ErrorLog(errMsg)
		panic(errMsg)
	}
	defer this.dataLock.RUnlock()

	return this.data[:BaseChallengeStageLenModelBll.GetData()]
}

//
// UpdatePlayer
// @Description:修改排行榜数据
// @receiver this
// @param challengedRank:排行榜排名
// @param playerChallenge:用户数据
//
func (this *globalChallengeStageSlice) UpdatePlayer(challengedRank int, playerChallenge *GlobalChallengeModel) {
	if challengedRank > len(this.data) {
		return
	}

	if isOk, prevStack, currStack := this.dataLock.Lock(systemConstant.DefaultLockTime); isOk == false {
		errMsg := fmt.Sprintf("Lock timeout! \n上一个堆栈:\n%s  \n当前堆栈:\n%s", prevStack, currStack)
		onlinelog.ErrorLog(errMsg)
		panic(errMsg)
	}
	defer this.dataLock.Unlock()

	this.data[challengedRank-1] = playerChallenge
}

//
// InitAndAddChallengeStageLast
// @Description:初始化并添加用户到页签末尾
// @receiver this
// @param playerId:用户id
// @param stageId:页签id
//
func (this *globalChallengeStageSlice) InitAndAddChallengeStageLast(playerId string, stageId int) *GlobalChallengeModel {
	if isOk, prevStack, currStack := this.dataLock.Lock(systemConstant.DefaultLockTime); isOk == false {
		errMsg := fmt.Sprintf("Lock timeout! \n上一个堆栈:\n%s  \n当前堆栈:\n%s", prevStack, currStack)
		onlinelog.ErrorLog(errMsg)
		panic(errMsg)
	}
	defer this.dataLock.Unlock()

	rank := len(this.data) + 1
	playerChallenge := GlobalChallengeBll.UpdateChallengePlayer(playerId, stageId, rank, false)

	this.data = append(this.data, playerChallenge)
	return playerChallenge
}
